In ASP.NET 2.0 and beyond, the core of Forms
authentication is the same as in ASP.NET 1.x. Most of the tricks and
techniques you have learned remain valid and usable. The most notable
change to Forms authentication in ASP.NET 2.0 and newer versions is the
introduction of a complementary API—the membership API. The membership
API provides a set of classes to let you manage users and roles.
Partnered with the FormsAuthentication class, the new Membership and RolesMembership
class supplies methods to manage user accounts—for adding or deleting a
new user and editing any associated user information such as e-mail
address and password. The Roles class creates and manages associations between users and roles. classes form a complete security toolkit for ASP.NET developers. The
What does the expression “managing user accounts” mean exactly? Simply put, it states that the Membership
class knows how to create a new user or change his or her password. How
do you create a user? Typically, you add a new record to some sort of
data store. If that’s the case, who is in charge of deciding which data
store to use and how to actually write the new user information? These
tasks represent the core functionality the membership API is designed
to provide.
The
membership API doesn’t bind you to a fixed data store and data scheme.
Quite the reverse, I’d say. It leaves you free to choose any data store
and scheme you want, but it binds you to a fixed API through which
users and roles are managed. The membership API is based on the
provider model , and it delegates to the selected provider the implementation of all the features defined by the API itself.
The Membership Class
Centered around the Membership
static class, the membership API shields you from the details of how
the credentials and other user information are retrieved and compared.
The Membership
class contains a few methods that you use to obtain a unique identity
for each connected user. This information can also be used with other
ASP.NET services, including role-based function enabling and
personalization.
Among
the members of the class are methods for creating, updating, and
deleting users, but not methods for managing roles and programmatically
setting what a user can and cannot do. For that you’ll have to turn to
the Roles class, which we’ll cover later.
The Membership
class defaults to a provider that stores user information in a SQL
Express database in a predefined format. If you want to use a custom
data store (such as a personal database), you can create your own
provider and just plug it in.
The Programming Interface of the Membership Class
Table 1 lists the properties exposed by the Membership class.
Table 1. Properties of the Membership Class
Property | Description |
---|
ApplicationName | A string to identify the application. Defaults to the application’s root path. |
EnablePasswordReset | Returns true if the provider supports password reset. |
EnablePasswordRetrieval | Returns true if the provider supports password retrieval. |
MaxInvalidPasswordAttempts | Returns the maximum number of invalid password attempts allowed before the user is locked out. |
MinRequiredNonAlphanumericCharacters | Returns the minimum number of punctuation characters required in the password. |
MinRequiredPasswordLength | Returns the minimum required length for a password. |
PasswordAttemptWindow | Returns
the number of minutes in which a maximum number of invalid password or
password answer attempts are allowed before the user is locked out. |
PasswordStrengthRegularExpression | Returns the regular expression that the password must comply with. |
Provider | Returns an instance of the provider being used. |
Providers | Returns the collection of all registered providers. |
RequiresQuestionAndAnswer | Returns true if the provider requires a password question/answer when retrieving or resetting the password. |
UserIsOnlineTimeWindow | Number of minutes after the last activity for which the user is considered on line. |
The Provider
property returns a reference to the membership provider currently in
use. As you’ll see in a moment, the provider is selected in the
configuration file. ASP.NET comes with a couple of predefined providers
that target MDF files in SQL Server Express and Active Directory.
However, many more membership providers are in the works from Microsoft
and third-party vendors, or you can even derive your own. You can
obtain the list of installed providers for a given application through
the Providers collection.
All
properties are static and read-only. All of them share a pretty simple
implementation. Each property just accesses the corresponding member on
the current provider, as shown here:
public static int PasswordAttemptWindow
{
get
{
Membership.Initialize();
return Membership.Provider.PasswordAttemptWindow;
}
}
As the name suggests, the Initialize method ensures that the internal structure of the Membership class is properly initialized and that a reference to the provider exists.
The
class supports fairly advanced functionality, such as estimating the
number of users currently using the application. It uses the value
assigned to the UserIsOnlineTimeWindow
property to determine this number. A user is considered on line if he
has done something with the application during the previous time
window. The default value for the UserIsOnlineTimeWindow property is 15 minutes. After 15 minutes of inactivity, a user is considered off line.
Table 2 details the methods supported by the Membership class. This list clarifies the tasks the class accomplishes.
Table 2. Methods of the Membership Class
Member | Description |
---|
CreateUser | Creates a new user and fails if the user already exists. The method returns a MembershipUser object representing any available information about the user. |
DeleteUser | Deletes the user corresponding to the specified name. |
FindUsersByEmail | Returns a collection of MembershipUser objects whose e-mail address corresponds to the specified e-mail. |
FindUsersByName | Returns a collection of MembershipUser objects whose user name matches the specified username. |
GeneratePassword | Generates a random password of the specified length. |
GetAllUsers | Returns a collection of all users. |
GetNumberOfUsersOnline | Returns the total number of users currently on line. |
GetUser | Retrieves the MembershipUser object associated with the current or specified user. |
GetUserNameByEmail | Obtains the user name that corresponds to the specified e-mail. If more users share the same e-mail, the first is retrieved. |
UpdateUser | Takes a MembershipUser object and updates the information stored for user. |
ValidateUser | Authenticates a user by using supplied credentials. |
Setting Up Membership Support
To
build an authentication layer based on the membership API, you start by
choosing the default provider and establish the data store. In the
simplest case, you can stay with the default predefined provider, which
saves user information in a local MDF file in SQL Server 2005 Express.
The
Web Site Administration Tool (WSAT) in Visual Studio provides a user
interface for creating and administering the registered users of your
application. Figure 1 provides a glimpse of the user interface.
To
add a new user or to edit properties of an existing one, you use the
links shown in the figure. When you edit the properties of a new user,
you use the page in Figure 2.
Validating Users
At
this point, we’re ready to write some code that uses the membership
API. Let’s start with the most common operation—authenticating
credentials. Using the features of the membership subsystem, you can
rewrite the code in the login page you saw previously to authenticate a
user as follows:
void LogonUser(object sender, EventArgs e)
{
string user = userName.Text;
string pswd = passWord.Text;
if (Membership.ValidateUser(user, pswd))
FormsAuthentication.RedirectFromLoginPage(user, false);
else
errorMsg.Text = "Sorry, yours seems not to be a valid account.";
}
This
code doesn’t look much different from what you would write for an
ASP.NET 1.x application, but there’s one big difference: the use of the
built-in ValidateUsersystem.web assembly: function. Here is the pseudocode of this method as it is implemented in the
public static bool ValidateUser(string username, string password)
{
return Membership.Provider.ValidateUser(username, password);
}
As
you can see, all the core functionality that performs the
authentication lives in the provider. What’s nice is that the name of
the provider is written in the web.config
Managing Users and Passwords
The Membership
class provides easy-to-use methods for creating and managing user data.
For example, to create a new user programmatically, all you do is place
a call to the CreateUser method:
Membership.CreateUser(userName, pswd);
To delete a user, you call the DeleteUser method:
Membership.DeleteUser(userName);
You can just as easily get information about a particular user by using the GetUser method. The method takes the username and returns a MembershipUser object:
MembershipUser user = Membership.GetUser("DinoE");
Once you’ve got a MembershipUser
object, you know all you need to know about a particular user, and you
can, for example, programmatically change the password (or other
user-specific information). An application commonly needs to execute
several operations on
passwords, including changing the password, sending a user her
password, or resetting the password, possibly with a question/answer
challenge protocol. Here is the code that changes the password for a
user:
MembershipUser user = Membership.GetUser("DinoE");
user.ChangePassword(user.GetPassword(), newPswd);
To use the ChangePassword
method, you must pass in the old password. In some cases, you might
want to allow users to simply reset their password instead of changing
it. You do this by using the ResetPassword method:
MembershipUser user = Membership.GetUser("DinoE");
string newPswd = user.ResetPassword();
In this case, the page that calls ResetPassword is also in charge of sending the new password to the user—for example, via e-mail. Both the GetPassword and ResetPassword
methods have a second overload that takes a string parameter. If
specified, this string represents the answer to the user’s “forgot
password” question. The underlying membership provider matches the
supplied answer against the stored answers; if a user is identified,
the password is reset or returned as appropriate.
Note
It
goes without saying that the ability to reset the password, as well as
support for the password’s question/answer challenge protocol, is
specific to the provider. You should note that not all the functions
exposed by the membership API are necessarily implemented by the
underlying provider. If the provider does not support a given feature,
an exception is thrown if the method is invoked. |